﻿using 实验1._1_Calc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

public class CalculateImpl : Calculate
{
    public string calculate(String infixExpression)
    {
        // 调用函数将中缀表达式转换为后缀表达式
        string postfix = infixToPostfix(infixExpression);
        // 后缀表达式求值
        return postfixValue(postfix);
    }
    string postfixValue(String postfixExpr)
    {
        Stack<double> result = new Stack<double>();
        double num = 0;
        double dotnum = 1;  // 小数点位数
        bool dot = false;   // 小数点标识
        bool numflag = false;   // 数字标识
        for (int i = 0; i < postfixExpr.Length; i++)
        {
            char ch = postfixExpr[i];
            // 出现空格
            if (char.IsWhiteSpace(ch))
            {
                dot = false;    // 重置小数点标志位
                dotnum = 1;     // 重置小数点位数
                if (numflag)
                {
                    // 这个if解决的是num为0时引发的歧义：操作数确实为0，或没有操作数
                    // 出现空格有两种情况：1.操作数后 2.运算符后
                    numflag = false;
                    result.Push(num);
                }
                
                num = 0;
                dot = false;
                // 可以出现连续两个空格，跳过
                while (i < postfixExpr.Length && char.IsWhiteSpace(postfixExpr[i]))
                {
                    i++;
                }   // while循环至少执行一次，所以需要i--
                i--;
                continue;
            }
            // 如果ch是运算符，并且结果栈中还有不少于两个运算数，则进行计算
            if (isOperators(ch) && result.Count >= 2)
            {
                // ch是运算符,且结果栈中不止一个元素
                double num_b = result.Pop();
                double num_a = result.Pop();
                double temp;
                switch (ch)
                {
                    case '+':
                        temp = num_a + num_b;
                        break;
                    case '-':
                        temp = num_a - num_b;
                        break;
                    case '%':
                        temp = num_a % num_b;
                        break;
                    case '*':
                        temp = num_a * num_b;
                        break;
                    case '/':
                        if (num_b == 0)
                        {
                            return "除数不能为0！";
                        }
                        temp = num_a / num_b;
                        break;
                    default:
                        return "未知的运算方式，太高深了！";
                }
                result.Push(temp);
                continue;   // 执行下一次循环，下面的代码不执行
            }
            // 出现小数点，后面的数字需要特殊处理
            if (ch == '.')
            {
                dot = true;
            }
            else
            {
                // 是数字
                if (dot)
                {
                    dotnum /= 10;
                    num = num + (ch - '0')*dotnum;
                }
                else if (ch == 'e')
                {
                    numflag = true;
                    num = (num == 0 ? 1 : num);
                    num *= Math.E;
                }
                else
                {
                    numflag = true;
                    num = num * 10 + (ch - '0');
                }
            }
        }
        // 返回结果
        if (result.Count>0)
        {
            return result.Pop().ToString();
        }
        else
        {
            return "0";
        }
        
    }

    bool isOperators(char ch)
    {
        switch (ch)
        { 
            case '+':
            case '-':
            case '*':
            case '/':
            case '%':
                return true;
            default :
                return false;
        }
    }
    
    // 将中缀表达式转换为后缀表达式
    public string infixToPostfix(string infixExpression)
    {
        
        infixExpression = infixExpression.Replace(" ", ""); // 提前消除空格
        Stack<char> operators = new Stack<char>();
        StringBuilder result = new StringBuilder();
        for (int i = 0; i < infixExpression.Length; i++)
        {
            // 如果最后一个字符是运算符，说明输入完整，需要跳过
            if (i == infixExpression.Length -1 && isOperators(infixExpression[i]))
            {
                continue;
            }
            char ch = infixExpression[i];
            switch (ch)
            {
                case '*':
                case '/':
                case '%':
                    // 遇到* /操作符，若栈顶也是*/操作符，先输出栈顶操作符
                    while (operators.Count > 0 && ("*/".IndexOf(operators.Peek()) >= 0))
                    {
                        char lastCh = operators.Pop();   // 出栈操作符，添加到结果字符串
                        result.Append(" ");
                        result.Append(lastCh);
                    }
                    operators.Push(ch); // 将操作符保存到栈中
                    result.Append(" ");
                    break;
                case '+':
                case '-':
                    // 遇到+ -操作符，先输出栈顶操作符，直到遇到左括号(
                    while (operators.Count > 0 && operators.Peek() != '(')
                    {
                        char lastCh = operators.Pop();   // 出栈操作符，添加到结果字符串
                        result.Append(" ");
                        result.Append(lastCh);
                    }
                    operators.Push(ch); // 将操作符保存到栈中
                    result.Append(" ");
                    break;
                case '(':
                    // 左括号( 直接入栈
                    operators.Push(ch);
                    result.Append(" ");
                    break;
                case ')':
                    // 右括号，输出栈中的操作符，直到遇到左括号
                    while (operators.Count > 0 && operators.Peek() != '(')
                    {
                        char lastCh = operators.Pop();  
                        result.Append(" ");
                        result.Append(lastCh);
                    }
                    result.Append(" ");
                    break;
                default:
                    // 其他情况，说明是操作数，直接添加到结果字符串
                    result.Append(ch);
                    break;
            }
        }
        // 剩下的所有操作符直接依次添加到最后面
        while (operators.Count > 0)
        {
            result.Append(" ");
            result.Append(operators.Pop());
        }
        result.Append(" ");
        return result.ToString();
    }
}
